﻿using System;
using Tao.OpenGl;

namespace Aeon.Framework
{

/// <summary>
/// Random noise plane mesh terrain class.
/// 
/// </summary>
public class Terrain : IObject
    {
    // --- Attributes:

    private AeonColor color;            // Color tone.
    private ITexture texture;           // Texture image.

    private Vertex[] vertexes;          // Terrain vertexes.
    private Int32[] triangles;          // Vertex triangles indexes.
    
    // --- Constructor:

    public Terrain(String key, Position center, Orientation face, UInt16 size, UInt16 tiles, UInt16 lod, AeonColor color, ITexture texture)
        : base(key,center,face)
        {
        this.color = color;
        this.texture = texture;
        
        ushort indices = (ushort)(lod*lod * 2 * 3);         // Number of triangle endpoints, 6 by tile.
	    ushort vertices = (ushort)((lod+1) * (lod+1));      // Number of vertices, 4 by tile.
	    ushort divisions = (ushort)Math.Sqrt(indices/6);    // Number of tiles.
        
        vertexes = genVertexes(vertices,divisions,tiles,size);
        triangles = genTriangles(indices,divisions);
        }
        
    // --- Internal Methods:
        
    private Vertex[] genVertexes(ushort vertices, ushort divisions, ushort tiles, ushort size)
        {
        Vertex[] array = new Vertex[vertices];
        
        Int32 cnt = vertices;
        Random png = new Random();
	    for (int x=0;x<=divisions;x++)
	        {
	        for (int z=0;z<=divisions;z++)
		        {
		        float tex_delta = 2.0f/divisions;
	            float delta = size/divisions;
	            
		        Vertex v = new Vertex();

			    v.X = (-0.5f * size) + (z*delta);
			    v.Z = (-0.5f * size) + (x*delta);
			    v.Y = (float)(5*((Math.Cos(v.X)*1.5f) + (Math.Sin(v.Z) * 1.5f) + png.Next()%50));

			    v.U = tiles*(z * tex_delta*0.5f);
			    v.V = tiles*(1.0f - x * tex_delta*0.5f);
			    
                array[--cnt] = v;
		        }
	        }
        
        return(array);
        }
        
    private Int32[] genTriangles(ushort indices, ushort divisions)
        {
        Int32[] array = new Int32[indices];
        
        Int32 cnt = indices;
	    for (int x=0;x<divisions;x++)
	        {
		    for (int z=0;z<divisions;z++)
		        {
			    int start = (x*(divisions+1)+z);
		
                array[--cnt] = start;
                array[--cnt] = start+1;
                array[--cnt] = start+divisions+1;
			    
		        array[--cnt] = start+1;
                array[--cnt] = start+divisions+2;
                array[--cnt] = start+divisions+1;
		        }
	        }
        
        return(array);
        }
    
    // --- External Methods:

    public override void Draw()
        {
        Gl.glTranslated(origin.xPos,origin.yPos,origin.zPos);
        Gl.glRotated(face.xAng,1,0,0);
        Gl.glRotated(face.yAng,0,1,0);
        Gl.glRotated(face.zAng,0,0,1);

        texture.Bind();
        
        Gl.glBegin(Gl.GL_TRIANGLES);    // Polygons.
        //Gl.glBegin(Gl.GL_LINES);      // Wireframe.
            
        foreach(Int32 i in triangles)
            {
            Gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

            Gl.glTexCoord2f(vertexes[i].U, vertexes[i].V);
            Gl.glVertex3f(vertexes[i].X, vertexes[i].Y, vertexes[i].Z);
            }
        
	    Gl.glEnd();
        }
        
    }
    
    
}